import * as d3 from 'd3'

const drag = simulation => {
  function dragstarted (d) {
    if (!d3.event.active) simulation.alphaTarget(0.3).restart()
    d.fx = d.x
    d.fy = d.y
  }

  function dragged (d) {
    d.fx = d3.event.x
    d.fy = d3.event.y
  }

  function dragended (d) {
    if (!d3.event.active) simulation.alphaTarget(0)
    d.fx = null
    d.fy = null
  }

  return d3.drag()
    .on('start', dragstarted)
    .on('drag', dragged)
    .on('end', dragended)
}

const colorScale1 = d3.scaleOrdinal(d3.schemeCategory10)
const colorScale2 = d3.scaleOrdinal(d3.schemeAccent)

function GenerateGraph (nodeDataset, edgeDataset, customConfigs) {
  let defaultConfigs = {
    width: 1000,
    height: nodeDataset.length > 5 ? nodeDataset.length / 4 * 400 : 400,
    forceStrength: -400,
    lineLength: 150,
    relTextSize: 13,
    r: 27 // node size
  }

  $.extend(true, defaultConfigs, customConfigs)

  document.getElementsByTagName('svg')[0].innerHTML = ''
  let svg = d3.select('svg')
  svg.attr('width', defaultConfigs.width).attr('height', defaultConfigs.height)

  let simulation = d3.forceSimulation(nodeDataset)
    .force('link', d3.forceLink(edgeDataset).id(d => d.id))
    .force('charge', d3.forceManyBody().strength(defaultConfigs.forceStrength))
    .force('center', d3.forceCenter(defaultConfigs.width / 2, defaultConfigs.height / 2))

  simulation.force('link').distance(defaultConfigs.lineLength)

  let links = svg.append('g')
    .selectAll('line')
    .data(edgeDataset)
    .enter()
    .append('line')
    .attr('stroke', d => colorScale2(d.relation))
    .attr('stroke-width', defaultConfigs.r / 10)

  let linksText = svg.append('g')
    .selectAll('text')
    .data(edgeDataset)
    .enter()
    .append('text')
    .style('font-size', defaultConfigs.relTextSize)
    .text(d => d.relation)

  let nodes = svg.selectAll('.circle')
    .data(nodeDataset)
    .enter()
    .append('g')
    .attr('transform', d => { return `translate(${d.x},${d.y})` })
    .on('click', function (d) {
      window.nodeInfo.name = d.name
      window.nodeInfo.type = d.type
    })
    .call(drag(simulation))

  nodes.append('circle')
    .attr('r', defaultConfigs.r)
    .attr('fill', d => colorScale1(d.type))

  nodes.append('text')
    .attr('y', '0.35em')
    .attr('fill', '#000000')
    .attr('text-anchor', 'middle')
    .style('font-size', defaultConfigs.r / 3)
    .text(d => d.name)

  simulation.on('tick', () => {
    links
      .attr('x1', d => d.source.x)
      .attr('y1', d => d.source.y)
      .attr('x2', d => d.target.x)
      .attr('y2', d => d.target.y)

    linksText
      .attr('x', d => (d.source.x + d.target.x) / 2)
      .attr('y', d => (d.source.y + d.target.y) / 2)

    nodes.attr('transform', d => { return `translate(${d.x},${d.y})` })
  })
}

export default {
  GenerateGraph
}
